/*
 * Created on 2005-3-30
 *
 */
package com.hd123.rumba.impex;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

import net.sf.hibernate.Hibernate;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.Transaction;
import net.sf.hibernate.type.Type;

import org.apache.log4j.Logger;

import com.hd123.rumba.domain.IDomain;
import com.hd123.rumba.domain.IDomainMgr;
import com.hd123.rumba.exception.BusinessException;
import com.hd123.rumba.exception.ParameterException;
import com.hd123.rumba.runtime.FormatSettings;
import com.hd123.rumba.runtime.HibernateSession;
import com.hd123.rumba.runtime.Manager;
import com.hd123.rumba.runtime.NamingMgr;
import com.hd123.rumba.sql.ResultPage;
import com.hd123.rumba.sql.SQLSubquery;
import com.hd123.rumba.user.IUser;
import com.hd123.rumba.util.StringUtil;

/**
 * @author caili
 */
public class ImpexMgr extends Manager {
  
  public static final String CAPTION_MANAGER = "导入导出管理员";
  
  private static ImpexMgr instance = null;

  public static ImpexMgr getInstance() {
    if (instance == null)
      instance = new ImpexMgr();
    return instance;
  }

  private ImpexMgr() {
    super();
  }

  public static final String PERMISSION_IMPEX = "导入导出.查看权";
  
  private Indicator createIndicator(IDomain domain, String object, String action, IDomain counterPart)
      throws ParameterException {
    if (domain == null) {
      throw new ParameterException("必须的参数domain不能为空.");
    }
    Indicator ind = new Indicator();
    ind.setDomain(domain);
    ind.setObject(object);
    ind.setAction(action);
    ind.setCounterPart(counterPart);
    return ind;
  }

  public Indicator getIndicator(String uuid) throws HibernateException {
    Indicator ind = null;
    if (uuid != null) {
      ind = (Indicator) getSession().load(Indicator.class, uuid);
    }
    return ind;
  }

  /**
   * 取得一个Indicator. 如果不存在, 根据create指示生成一个新的或返回null
   * 
   * @param domain
   *          indicator所在的域. 一般是企业域.
   * @param object
   * @param action
   * @param counterPart
   * @param create
   *          是否生成一个新的, 如果不存在的话
   * @return
   * @throws HibernateException
   */
  public Indicator getIndicator(IDomain domain, String object, String action, IDomain counterPart,
      boolean create) throws HibernateException, BusinessException {
    this.checkParameterNotNull(domain, "domain");
    this.checkParameterNotNull(object, "object");
    this.checkParameterNotNull(counterPart, "counterPart");
    if (!action.equals(Indicator.EXPORT) && !action.equals(Indicator.IMPORT)) {
      throw new ParameterException("参数action的取值不正确.");
    }
    List list = getSession().find(
        "from Indicator i where i.domain.uuid=? and i.object=? and i.action=? and i.counterPart.uuid=?",
        new Object[] {
            domain.getUuid(), object, action, counterPart.getUuid() }, new Type[] {
            Hibernate.STRING, Hibernate.STRING, Hibernate.STRING, Hibernate.STRING });
    Indicator ind = null;
    if (list.size() > 0) {
      ind = (Indicator) list.get(0);
      getLogger().debug("indicator retrieved.");
    } else if (create) {
      ind = createIndicator(domain, object, action, counterPart);
      this.saveIndicatorT(ind);
      getLogger().debug("indicator created.");
    }
    return ind;
  }

  public ResultPage createAllIndiactorsPage(IDomain domain, int pageSize, int page) throws Exception,
      ParameterException {
    if (domain == null) {
      throw new ParameterException("必须的参数domain不能为空.");
    }
    SQLSubquery sq = new SQLSubquery();
    sq.addSelect("i");
    sq.addFrom("Indicator i");
    sq.addWhere("i.domain.uuid=?", domain.getUuid());
    sq.addOrder("i.counterPart.uuid, i.object");
    return ResultPage.createHibernateResultPage(getSession(), sq, pageSize, page);
  }

  public ResultPage createCounterPartIndiactorsPage(IDomain domain, IDomain counterPart, int pageSize,
      int page) throws Exception, ParameterException {
    if (domain == null) {
      throw new ParameterException("必须的参数domain不能为空.");
    }
    if (counterPart == null) {
      throw new ParameterException("必须的参数counterPart不能为空.");
    }
    SQLSubquery sq = new SQLSubquery();
    sq.addSelect("i");
    sq.addFrom("Indicator i");
    sq.addWhere("i.domain.uuid=?", domain.getUuid());
    sq.addWhere("and i.counterPart.uuid=?", counterPart);
    sq.addOrder("i.object");
    return ResultPage.createHibernateResultPage(getSession(), sq, pageSize, page);
  }

  public ResultPage createObjectIndiactorsPage(IDomain domain, String object, int pageSize, int page)
      throws Exception, ParameterException {
    if (domain == null) {
      throw new ParameterException("必须的参数domain不能为空.");
    }
    if (object == null) {
      throw new ParameterException("必须的参数object不能为空.");
    }
    SQLSubquery sq = new SQLSubquery();
    sq.addSelect("i");
    sq.addFrom("Indicator i");
    sq.addWhere("i.domain.uuid=?", domain.getUuid());
    sq.addWhere("and i.object=?", object);
    sq.addOrder("i.counterPart.uuid");
    return ResultPage.createHibernateResultPage(getSession(), sq, pageSize, page);
  }

  public void saveIndicatorT(Indicator ind) throws HibernateException, ParameterException {
    Transaction tx = null;
    try {
      tx = HibernateSession.beginTransaction();
      saveIndicator(ind);
      HibernateSession.commit(tx);
    } catch (HibernateException e) {
      if (tx != null) {
        HibernateSession.rollback(tx);
      }
      Logger.getLogger(this.getClass()).error(e.getMessage());
      throw e;
    }
  }

  public void saveIndicator(Indicator ind) throws HibernateException, ParameterException {
    this.checkParameterNotNull(ind, "ind");
    ind.setLastModified(new Date());
    getSession().save(ind);
  }

  public ImpexLog createImpexLog(Indicator ind, IUser user) throws HibernateException, BusinessException {
    this.checkParameterNotNull(ind, "ind");
    this.checkParameterNotNull(user, "user");
    ImpexLog log = new ImpexLog();
    log.setIndicator(ind);
    log.setUserFullLogin(user.getFullLogin());
    log.setCurrentExportCondition(ind.getExportCondition());
    log.setStartTime(new Date());
    return log;
  }

  public ImpexLog getImpexLog(String uuid) throws HibernateException {
    ImpexLog log = null;
    if (uuid != null) {
      log = (ImpexLog) getSession().load(ImpexLog.class, uuid);
    }
    return log;
  }

  public void saveImpexLog(ImpexLog log) throws HibernateException, ParameterException {
    log.setLastModified(new Date());
    Indicator ind = getIndicator(log.getIndicator().getUuid());
    if (ind == null)
      ind = log.getIndicator();
    saveIndicator(ind);
    log.setIndicator(ind);
    getSession().saveOrUpdate(log);
    // getSession().flush();
    // getSession().clear();
  }

  public void saveImpexLogT(ImpexLog log) throws Exception {
    Transaction tx = null;
    try {
      tx = HibernateSession.beginTransaction();
      saveImpexLog(log);
      HibernateSession.commit(tx);
    } catch (HibernateException e) {
      if (tx != null) {
        HibernateSession.rollback(tx);
      }
      Logger.getLogger(this.getClass()).error(e.getMessage());
      throw e;
    }
  }

  public void removeImpexLog(ImpexLog log) throws Exception {
    getSession().delete(log);
  }

  /**
   * 取得ind的日志列表, 其状态为state
   * 
   * @param ind
   * @param state
   * @return
   * @throws HibernateException
   * @throws ParameterException
   */
  public List createImpexLogsList(Indicator ind, String state, String userLogin) throws HibernateException,
      ParameterException {
    if (ind == null) {
      throw new ParameterException("必须的参数ind不能为空.");
    }
    if (state == null) {
      throw new ParameterException("必须的参数state不能为空.");
    }
    if (userLogin == null) {
      throw new ParameterException("必须的参数userLogin不能为空.");
    }
    return getSession().find(
        "from ImpexLog log where log.indicator.uuid=? and log.state=? and userFullLogin = ?", new Object[] {
            ind.getUuid(), state, userLogin }, new Type[] {
            Hibernate.STRING, Hibernate.STRING, Hibernate.STRING });
  }

  public ResultPage createImpexLogsPage(Indicator ind, int pageSize, int page) throws Exception {
    if (ind == null) {
      throw new ParameterException("必须的参数ind不能为空.");
    }
    SQLSubquery sq = new SQLSubquery();
    sq.addSelect("log");
    sq.addFrom("ImpexLog log");
    sq.addWhere("log.indicator.uuid=?", ind.getUuid());
    return ResultPage.createHibernateResultPage(getSession(), sq, pageSize, page);
  }

  //  /**
  //   * 生成并保存导出日志(ImpexLog), 标记状态为导出中, 记录本次导出的数据条件值, 设置下一次导出的数据条件值,
  //   * 记录导出开始时间和数据生成时间
  //   *
  //   * @param ind
  //   * @param newExportCondition
  //   * @param sr
  //   * @return
  //   * @throws HibernateException
  //   */
  //  public ImpexLog createAndSaveExportLog(Indicator ind,
  //      ExportCondition newExportCondition)
  //      throws HibernateException, ParameterException {
  //    ImpexLog exportLog = createImpexLog(ind);
  //    exportLog.setCurrentExportCondition(ind.getExportCondition());
  //    exportLog.setNewExportCondition(newExportCondition);
  //    exportLog.setState(ImpexLog.EXPORTING);
  //    exportLog.setEndTime(new Date());
  //    exportLog.setDescription(sr.getMessage(ImpexResult.EXPORT));
  //    getSession().save(ind);
  //    getSession().save(exportLog);
  //    return exportLog;
  //  }

  /**
   * 标记导出完成. 根据导出日志的UUID查到导出日志记录. 如果该记录的状态为导出中, 则执行以下操作 <br>
   * 根据导出日志记录找到指示清单中的记录(Indicator) 对同一指示的其它状态为"导出中"的日志记录, 都标注成"取消" <br>
   * 标记此日志记录的状态为导出完成, 记录导出时间 <br>
   * 用此日志记录中的新条件值修改指示记录中的条件值.
   * 
   * @param exportLogUuid
   * @throws HibernateException
   */
  public void commitExport(String exportLogUuid) throws HibernateException, ParameterException {
    ImpexLog exportLog = getImpexLog(exportLogUuid);
    if (exportLog == null) {
      String msg = "找不到" + exportLogUuid + "指示的导出日志.";
      Logger.getLogger(this.getClass()).error(msg);
      throw new HibernateException(msg);
    }
    List list = createImpexLogsList(exportLog.getIndicator(), ImpexLog.EXPORTING, exportLog
        .getUserFullLogin());
    for (int i = 0; i < list.size(); ++i) {
      ImpexLog log = (ImpexLog) list.get(i);
      log.setState(ImpexLog.ABORTED);
      getSession().update(log);
    }
    exportLog.setState(ImpexLog.COMMITED);
    Date commitTime = new Date();
    exportLog.setCommitTime(commitTime);
    getSession().update(exportLog);
    Indicator ind = exportLog.getIndicator();
    ind.setExportCondition(exportLog.getNewExportCondition());
    ind.setLastActionTime(commitTime);
    getSession().update(ind);
  }

  public void commitExportT(String exportLogUuid) throws HibernateException, ParameterException {
    Transaction tx = null;
    try {
      tx = getSession().beginTransaction();
      commitExport(exportLogUuid);
      tx.commit();
    } catch (HibernateException e) {
      if (tx != null) {
        tx.rollback();
      }
      Logger.getLogger(this.getClass()).error(e.getMessage());
      throw e;
    }
  }

  public void abortExport(String exportLogUuid, String msg) throws HibernateException, ParameterException {
    ImpexLog exportLog = getImpexLog(exportLogUuid);
    if (exportLog == null) {
      String errmsg = "找不到" + exportLogUuid + "指示的导出日志.";
      Logger.getLogger(this.getClass()).error(errmsg);
      throw new HibernateException(errmsg);
    }
    exportLog.setState(ImpexLog.ABORTED);
    String s = msg;
    if (s.length() > 250)
      s = msg.substring(0, 250);
    exportLog.setDescription(s);
    getSession().update(exportLog);
    Indicator ind = exportLog.getIndicator();
    ind.setLastActionTime(new Date());
    getSession().update(ind);
  }

  public void abortExportT(String exportLogUuid, String msg) throws HibernateException, ParameterException {
    Transaction tx = null;
    try {
      tx = getSession().beginTransaction();
      abortExport(exportLogUuid, msg);
      tx.commit();
    } catch (HibernateException e) {
      if (tx != null) {
        tx.rollback();
      }
      Logger.getLogger(this.getClass()).error(e.getMessage());
      throw e;
    }
  }

  ////////////////////////
  // Utilitities

  public String exportInteger(Integer value) {
    if (value == null)
      return null;
    else
      return StringUtil.stringToXml(value.toString());
  }

  public String exportString(String value) {
    if (value == null)
      return null;
    else
      return StringUtil.stringToXml(value);
  }

  public String exportDatetime(Date value) {
    if (value == null)
      return null;
    else
      return StringUtil.stringToXml(FormatSettings.formatDatetime(FormatSettings.SDFyMdHms, value));
  }

  public String exportBigDecimal(BigDecimal value) {
    if (value == null)
      return null;
    else
      return StringUtil.stringToXml(value.toString());
  }

  public String exportBoolean(Boolean value) {
    if (value == null)
      return null;
    else
      return value.toString();
  }

  public Integer importInteger(String value) throws Exception {
    if (value == null)
      return null;
    else
      return new Integer(value);
  }

  public String importString(String value) throws Exception {
    return value;
  }

  public Date importDatetime(String value) throws Exception {
    if (value == null || value.equals(new String("")))
      return null;
    else
      try {
        return FormatSettings.parseDatetime(FormatSettings.SDFyMdHms, value);
      } catch (Exception e) {
        return FormatSettings.parseDatetime(FormatSettings.SDFyMd, value);
      }
  }

  public BigDecimal importBigDecimal(String value) throws Exception {
    if (value == null || value.equals(new String("")))
      return null;
    else
      return new BigDecimal(value);
  }

  public Boolean importBoolean(String value) throws Exception {
    if (value == null || value.equals(new String("")))
      return null;
    else
      return value.equalsIgnoreCase("true") ? Boolean.TRUE : Boolean.FALSE;
  }

  public IDomain importDomainByUuid(String domainUuid, String Caption) throws Exception {
    if (domainUuid == null || domainUuid.equals(new String("")))
      return null;
    else {
      IDomain domain = ((IDomainMgr) NamingMgr.getInstance().lookupMgr(IDomainMgr.class))
          .getDomain(domainUuid);
      if (domain == null) {
        Logger.getLogger(this.getClass()).error(
            "导入 " + Caption + "(Uuid=" + domainUuid + ") 在系统中不存在，需要先导入相应的资料。");
        throw new Exception("导入 " + Caption + "(Uuid=" + domainUuid + ") 在系统中不存在，需要先导入相应的资料。");
      }
      return domain;
    }
  }
}
